/*
Copyright (C) 2016 Marien Raat

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "field.h"
#include "config.h"

#include <math.h>
#include <iostream>

Field::Field(b2World *world, sf::Vector2f size)
{
    initialize(world, size);
}

void Field::initialize(b2World *world, sf::Vector2f size)
{
   this->world = world;
   if (client) generateVertices(size);
   size /= SCALE_F;
   generateWalls(b2Vec2(size.x, size.y));
}

void Field::setTextures(sf::Texture *fieldTexture,
                        sf::Texture *grassTexture)
{
    this->fieldTexture = fieldTexture;
    fieldSprite.setTexture(*fieldTexture);
    fieldSprite.setColor(sf::Color(255, 255, 255, 200));
    this->grassTexture = grassTexture;
}

void Field::draw(sf::RenderTarget *target)
{
    target->draw(grassVertices, grassTexture);
    target->draw(fieldSprite);
}

void Field::generateVertices(sf::Vector2f size)
{
    sf::Vector2u textureSize = grassTexture->getSize();
    int texturesInWidth = ceil(size.x / (float) textureSize.x),
        texturesInHeight = ceil(size.y / (float) textureSize.y);

    grassVertices.resize(4 * texturesInWidth * texturesInHeight);
    grassVertices.setPrimitiveType(sf::Quads);

    for (int x = 0; x < texturesInWidth; x++) {
        for (int y = 0; y < texturesInHeight; y++) {
            sf::Vector2f position(x * textureSize.x,
                                  y * textureSize.y);
            sf::Vector2f tileSize = sf::Vector2f(textureSize.x,
                                                 textureSize.y);

            if (x == (texturesInWidth - 1)) {
                // Adjust the size of the tile to not overstep
                tileSize.x = textureSize.x -
                    (((float) texturesInWidth) -
                     (size.x / (float) textureSize.x)) *
                    (float) textureSize.x;
            }
            if (y == (texturesInHeight - 1)) {
                // Adjust the size of the tile to not overstep
                tileSize.y = textureSize.y -
                    (((float) texturesInHeight) -
                     (size.y / (float) textureSize.y)) *
                    (float) textureSize.y;
            }

            int i = 4 * x * texturesInHeight + 4 * y;

            grassVertices[i].position = position;
            grassVertices[i + 1].position = position +
                sf::Vector2f(tileSize.x, 0);
            grassVertices[i + 2].position = position + tileSize;
            grassVertices[i + 3].position = position +
                sf::Vector2f(0, tileSize.y);

            grassVertices[i].texCoords = sf::Vector2f(0, 0);
            grassVertices[i + 1].texCoords =
                sf::Vector2f(tileSize.x, 0);
            grassVertices[i + 2].texCoords = tileSize;
            grassVertices[i + 3].texCoords =
                sf::Vector2f(0, tileSize.y);
        }
    }
}

void Field::generateWalls(b2Vec2 size)
{
    b2BodyDef topBodyDef;
    topBody = world->CreateBody(&topBodyDef);

    b2ChainShape topChainShape;
    b2Vec2 topChain[6] = {
        b2Vec2(0, 0.4 * size.y),
        b2Vec2(0, 0.25 * size.y),
        b2Vec2((1.0 / 12.0) * size.x, 0),
        b2Vec2((1.0 - (1.0 / 12.0)) * size.x, 0),
        b2Vec2(size.x, 0.25 * size.y),
        b2Vec2(size.x, 0.4 * size.y)
    };
    topChainShape.CreateChain(topChain, 6);
    topBody->CreateFixture(&topChainShape, 1);

    b2BodyDef bottomBodyDef;
    bottomBody = world->CreateBody(&bottomBodyDef);

    b2ChainShape bottomChainShape;
    b2Vec2 bottomChain[6];
    // Mirror vertically
    for (int i = 0; i < 6; i++)
        bottomChain[i] = b2Vec2(topChain[i].x,
                                size.y - topChain[i].y);
    bottomChainShape.CreateChain(bottomChain, 6);
    bottomBody->CreateFixture(&bottomChainShape, 1);
}
